<template>
  <el-dialog
    custom-class="cropper-img__dialog"
    v-bind="$attrs"
    :title="title"
    :visible.sync="visible"
    :width="width"
    :before-close="handleClose"
  >
    <!-- <div class="tooltip-text__box">
      <i class="el-icon-warning yellow" />
    </div> -->
    <div class="cropper-img-container" :style="styleVar">
      <!-- 编辑区域 -->
      <div class="cropper-area">
        <div ref="cropperTarget" class="target-img">
          <img v-if="original" id="croppedImg" ref="image" class="cropped-img" alt="裁剪图片">
        </div>
        <div class="cropper-buttons">
          <el-row :gutter="24">
            <el-col :span="14">
              <div style="text-align: left; margin-left: 5px;">
                <el-upload
                  action="/api/file/upload"
                  :headers="myHeaders"
                  :with-credentials="true"
                  :show-file-list="false"
                  :on-success="handleAvatarSuccess"
                  :before-upload="beforeAvatarUpload"
                >
                  <el-link type="primary" :underline="false">重新上传</el-link>
                </el-upload>
              </div>
            </el-col>
            <el-col :span="2">
              <el-tooltip content="放大" placement="top">
                <i class="el-icon-circle-plus-outline cursor-pointer" @click="handleScale(0.1)" />
              </el-tooltip>
            </el-col>
            <el-col :span="2">
              <el-tooltip content="缩小" placement="top">
                <i class="el-icon-remove-outline cursor-pointer" @click="handleScale(-0.1)" />
              </el-tooltip>
            </el-col>
            <el-col :span="2">
              <el-tooltip content="逆时针旋转" placement="top">
                <i class="el-icon-refresh-left cursor-pointer" @click="handleRotate(-90)" />
              </el-tooltip>
            </el-col>
            <el-col :span="2">
              <el-tooltip content="顺时针旋转" placement="top">
                <i class="el-icon-refresh-right cursor-pointer" @click="handleRotate(90)" />
              </el-tooltip>
            </el-col>
            <el-col :span="2">
              <el-tooltip content="重置" placement="top">
                <i class="el-icon-refresh cursor-pointer" @click="handleRefresh" />
              </el-tooltip>
            </el-col>
          </el-row>
        </div>
      </div>
      <!-- 预览效果区域 -->
      <div class="preview-area">
        <div class="effect-drawing">
          <div class="preview" />
        </div>
        <p class="preview-title">预览效果</p>
        <div v-if="circlePreview" class="effect-drawing effect-drawing__circle">
          <div class="preview" />
        </div>
      </div>
    </div>

    <span slot="footer" class="dialog-footer">
      <el-button size="small" @click="handleCancel">取 消</el-button>
      <el-button type="primary" size="small" @click="handleConfirm">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script>
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { getToken, getSsoToken } from '@/util/auth'
// import { Loading } from 'element-ui'
import axios from 'axios'
// 给dialog设置loading
// const serviceLoading = ({ node, loadingText, lock = true }) => {
//   return this.$loading({
//     target: document.querySelector(node),
//     text: loadingText,
//     lock
//   })
// }

export default {
  name: 'CropperImgDialog',
  props: {
    title: {
      type: String,
      default: '裁剪图片'
    },
    visible: {
      type: Boolean,
      default: false
    },
    width: { // Dialog 宽度
      type: String,
      default: '705px'
    },
    cropperFile: {
      type: Object,
      default: () => ({
        original: '', // 原图
        url: '',
        type: '',
        name: ''
      })
    },
    cropBoxSizes: { // 裁剪区、预览图宽高比例
      type: Object, // Object<key: string, value: number>
      default: () => ({
        width: 120,
        height: 120
      })
    },
    props: { // 自定义 cropperFile Props
      type: Object,
      default: () => ({
        original: 'original',
        url: 'url',
        name: 'name',
        type: 'type'
      })
    },
    cropperOption: { // 自定义cropper配置项
      type: Object,
      default: () => ({})
    },
    circlePreview: { // 环形预览图显隐
      type: Boolean,
      default: true
    },
    /**
     * 自定义事件
     */
    beforeClose: {
      type: Function,
      default: null
    },
    cancel: {
      type: Function,
      default: null
    },
    confirm: {
      type: Function,
      default: null
    }
  },
  data() {
    this.myHeaders = {
      'Token': getToken(),
      'SsoToken': getSsoToken()
    }
    return {
      cropper: null,
      cropped: {},
      effectDrawing: '',
      original: '',
      name: '',
      type: ''
    }
  },
  computed: {
    styleVar: function() {
      return {
        '---wdith': this.cropBoxSizes.width + 'px',
        '---height': this.cropBoxSizes.height + 'px'
      }
    }
  },
  watch: {
    cropperFile: {
      handler: function(obj) {
        this.cropped = obj
        // this.original = obj[this.props.original]
        this.original = obj.original
      },
      immediate: true

    },
    original: {
      immediate: true,
      handler(val) {
        if (val) {
          var xhr = new XMLHttpRequest()
          const imgReg = /\.(SVG|svg)$/
          if (!imgReg.test(val)) {
            xhr.responseType = 'blob'
          }
          xhr.open('get', window.location.origin + '/api/' + this.original, true)
          // xhr.setRequestHeader('Authorization', `Basic ${Base64.encode(
          //   `${website.clientId}:${website.clientSecret}`
          // )}`)
          // xhr.setRequestHeader('Blade-Auth', 'bearer ' + getToken())
          xhr.setRequestHeader('Token', getToken())
          xhr.onreadystatechange = res => {
            const { readyState, status } = res.target
            if (readyState === 4 && status === 200) {
              this.type = xhr.getResponseHeader('Content-Type')
              const imgRef = this.$refs.image
              if (!imgReg.test(val)) {
                imgRef.src = URL.createObjectURL(xhr.response)
                imgRef.onLoad = () => {
                  URL.revokeObjectURL(imgRef.src)
                }
              } else {
                const b64 = window.btoa(unescape(encodeURIComponent(res.currentTarget.responseText)))
                imgRef.src = `data:image/svg+xml;base64,${b64}`
              }
              this.instantiateCropper()
            }
          }
          xhr.send()
        }
      }
    }
    // visible: {
    //   handler: async function(value) {
    //     this.instantiateCropper()
    //   }
    // }
  },
  methods: {
    instantiateCropper() {
      if (this.visible) {
        this.handleDestroy()
        this.$nextTick(() => {
          this.initialize()
        })
      }
    },
    initialize() {
      const ref = this.$refs.image
      if (!ref) {
        return
      }
      // const self = this
      this.cropper = new Cropper(ref, {
        ready() {
          // self.setCropBoxData(this.cropper)
          // this.key = new Date().getTime()
        },
        aspectRatio: 5 / 5,
        viewMode: 1, // 裁剪框不超过图片容器的范围
        dragMode: 'move', // 图片容器可移动
        preview: '.preview', // 预览DOM（支持类型：String/Array）
        background: false, // 是否在容器内显示网格背景
        zoomOnWheel: true, // 是否允许通过鼠标滚轮缩放图片
        cropBoxMovable: true, // 是否允许通过拖动来移动裁剪框
        cropBoxResizable: true, // 是否允许通过拖动来调整裁剪框的大小
        movable: true, // 是否可以移动图片
        rotatable: true, // 是否可以旋转图片
        ...this.cropperOption // 自定义配置项
      })
    },
    setCropBoxData(cropper) { // 设置裁剪区域
      const { width, height } = cropper.getImageData()
      // 根据头像框的宽高，计算裁剪出裁剪框宽高的比例
      const cropWidth = this.cropBoxSizes.width
      const cropHeight = this.cropBoxSizes.height
      const cropRotate = ((width + height) / (cropWidth + cropHeight)) / 1.7
      const setCropWidth = cropRotate * cropWidth
      const setCropheight = cropRotate * cropHeight
      // 计算裁剪框偏移位置
      const containerWidth = (this.$refs.cropperTarget.clientWidth - width) / 2 // 图片容器宽度 - 图片所占用的宽度 / 2 = 单边剩余空间
      const containerHeight = (this.$refs.cropperTarget.clientHeight - height) / 2
      const setCropLeft = ((width - setCropWidth) / 2) + containerWidth // 图片所占用的宽度 - 裁剪框的宽度 / 2 + 单边剩余空间 = 裁剪框左右居中的位置
      const setCropTop = ((height - setCropheight) / 2) + containerHeight
      cropper.setCropBoxData({
        left: setCropLeft,
        top: setCropTop,
        width: setCropWidth,
        height: setCropheight
      })
    },
    handleClose(done) {
      if (this.beforeClose instanceof Function) {
        this.beforeClose(() => {
          this.$emit('update:visible', false)
        })
        return
      }
      done()
    },
    handleCancel() {
      if (this.cancel instanceof Function) {
        this.cancel()
        return
      }
      this.$emit('update:visible', false)
    },
    async handleConfirm() {
      if (!this.cropper) {
        this.$message.error('裁剪图片失败')
        return
      }
      await this.$emit('update:visible', false)
      if (this.confirm instanceof Function) {
        const formData = this.getFormData()
        this.submitUpload(formData)
      }
    },
    submitUpload(formData) {
      axios.post('/api/file/upload', formData, {
        headers: { 'Content-Type': 'multipart/form-data', ...this.myHeaders }
      }).then(response => {
        this.confirm(response.data, this.original)
      }).catch(error => {
        console.error('上传失败', error)
      })
    },
    handleRotate(value) { // 旋转
      this.cropper.rotate(value)
    },
    handleScale(value) { // 放大/缩小
      this.cropper.zoom(value)
    },
    handleRefresh() { // 重置
      this.cropper.reset()
      // 重置后需要重新设置裁剪框裁剪的区域
      const self = this
      this.$nextTick(() => {
        self.setCropBoxData(this.cropper)
      })
    },
    handleDestroy() {
      if (this.cropper) {
        // this.cropper.clear()
        this.cropper.destroy()
      }
      this.cropper = null
    },
    /**
     * formData.append(key, value)
     * @param {string} key
     * @param {*} value
     * @return formData
     */
    getFormData(key = 'file', value) {
      const raw = value || this.getCroppedFileRaw()
      const formData = new FormData()
      formData.append(key, raw)
      return formData
    },
    getCroppedBase64() {
      const base64 = (this.cropper.getCroppedCanvas({
        imageSmoothingQuality: 'medium'
      })).toDataURL(this.type, 0.9) // 指定jpeg图片类型，并减低输出图片质量，避免上传图片裁剪后体积变大
      return base64
    },
    /**
     * @return raw 二进制文件流
     */
    getCroppedFileRaw() {
      const fileName = this.name || this.original.split('/')[this.original.split('/').length - 1]// this.getFileName()
      const base64 = this.getCroppedBase64()
      const raw = this.base64toFile(base64, fileName)
      return raw
    },
    base64toFile(base64Code, filename) {
      const arr = base64Code.split(',')
      const bstr = atob(arr[1])
      let n = bstr.length
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      // const type = this.getFileType()
      return new File([u8arr], `${filename}`, {
        type: this.type
      })
    },
    getFileName() {
      const name = this.cropped[this.props.name] || this.name
      if (name) {
        return name
      }
      const url = this.cropped[this.props.url] || this.original
      return url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'))
    },
    getFileType() {
      const type = this.cropped[this.props.type] || this.type
      if (type) {
        return type
      }
      const url = this.cropped[this.props.url] || this.original
      return url.substring(url.lastIndexOf('.') + 1, url.length)
    },
    beforeAvatarUpload(file) {
      this.type = file.type
      this.name = file.name
      // const imgReg = /\.(jpg|jpeg|png)$/
      // const isLtM = file.size / 1024 / 1024 < 5
      // if (!imgReg.test(file.name.toLowerCase())) {
      //   this.$message.error('上传图片只能是jpg/jpeg/png格式!')
      // }
      // if (!isLtM) {
      //   this.$message.error('上传图片文件大小不能超过 5MB!')
      // }
      // // this.imgLoading = true
      // return imgReg.test(file.name.toLowerCase()) && isLtM
      const typeArry = ['.jpg', '.png', '.bmp', '.JPG', '.PNG', '.BMP', '.svg', '.SVG']
      const type = file.name.substring(file.name.lastIndexOf('.'))
      const isImage = typeArry.indexOf(type) > -1
      if (!isImage) {
        this.$message.warning('图片支持jpg、bmp、png、svg格式')
      }
      return isImage
    },
    handleAvatarSuccess(res) {
      this.original = res.data || ''
      this.instantiateCropper()
    }
  }
}
</script>

<style lang="scss">
.cropper-img__dialog {
  .yellow{
    color: rgb(255,158,77);
    margin-right: 3px;
  }
  .el-dialog__body {
    padding: 20px;
  }
  .dialog-footer {
    text-align: center;
    .el-button--primary{
      background-color: #ED5353;
    }
    .el-button--primary:hover{
      background-color: #ED5353;
    }
  }
  // 提示
  .tooltip-text__box {
    width: calc(100% - 16px * 2);
    padding: 0 16px;
    height: 48px;
    display: flex;
    align-items: center;
    background: #FFF6ED;
    border-radius: 2px;
    font-size: 14px;
    color: #323233;
    font-weight: 400;
    margin-bottom: 20px;
    .tooltip-icon {
      width: 16px;
      height: 16px;
      margin-right: 8px;
    }
  }
  // 主容器
  .cropper-img-container {
    display: flex;
    .cropper-area {
      width: calc(100% - 120px - 40px);
    }
    .preview-area {
      width: 120px;
      margin-left: 39px;
      text-align: center;
    }
  }
  // 编辑区域
  .cropper-area {
    .target-img {
      width: 505px;
      height: 380px;
      border: 1px dashed #eee;
      // overflow: hidden;
      display: flex;
      align-items: center;
      justify-content: center;
      // background-color: gray;
      .cropped-img {
        display: block;
        width: 100%;
        height: 100%;
      }
      .replacePhoto{
        display: flex;
        flex-direction: column;
        justify-content: center;
      }
    }
    .cropper-buttons {
      width: calc(100% + 2px);
      text-align: center;
      padding-top: 20px;
      .el-col {
        border-bottom: none;
        padding: 0px 10px !important;
      }
      .cursor-pointer {
        cursor: pointer;
      }
    }
  }
  // 预览效果
  .preview-area {
    .preview-title {
      margin-top: 5px;
      font-size: 14px;
      color: #999999;
      line-height: 20px;
      font-weight: 400;
    }
    .effect-drawing__demo {
      width: 100%;
      height: 100%;
    }
    .effect-drawing {
      width: var(---wdith);
      height: var(---height);
      border: 1px dashed #eee;
      overflow: hidden;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      .preview {
        width: 100%;
        height: 100%;
      }
    }
    .effect-drawing__circle {
      border-radius: 50%;
    }
    .effect-drawing + .effect-drawing {
      margin-top: 20px;
    }
  }
}
</style>
